package com.hsjk.szwj.module.pay.controller.app.refund;

import cn.hutool.core.util.ObjectUtil;
import com.hsjk.szwj.framework.common.exception.ServiceException;
import com.hsjk.szwj.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.hsjk.szwj.framework.common.util.spring.SpringBeansUtil;
import com.hsjk.szwj.module.pay.controller.AbstractPayOrderController;
import com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg;
import com.hsjk.szwj.module.pay.dal.dataobject.config.MchAppConfigContext;
import com.hsjk.szwj.module.pay.dal.dataobject.order.RefundOrderDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchAppDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchInfoDO;
import com.hsjk.szwj.module.pay.exception.ResponseException;
import com.hsjk.szwj.module.pay.service.ConfigContextQueryService;
import com.hsjk.szwj.module.pay.service.IChannelRefundNoticeService;
import com.hsjk.szwj.module.pay.service.IMchAppService;
import com.hsjk.szwj.module.pay.service.IMchInfoService;
import com.hsjk.szwj.module.pay.service.RefundOrderProcessService;
import com.hsjk.szwj.module.pay.service.RefundOrderService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * @author chenjiawei
 * @desc
 * @Date 2023/08/25 01:00
 **/
@Tag(name = "应用端 - 退款通知入相关接口")
@RestController
@RequestMapping("/refund")
@Validated
@Slf4j
public class ChannelRefundNoticeController extends AbstractPayOrderController {
    @Resource
    private RefundOrderService refundOrderService;
    @Resource
    private ConfigContextQueryService configContextQueryService;
    @Resource
    private RefundOrderProcessService refundOrderProcessService;
    @Resource
    private IMchInfoService mchInfoService;
    @Resource
    private IMchAppService mchAppService;
    /**
     * 异步回调入口
     **/
    @ResponseBody
    @RequestMapping(value = {"/notify/{ifCode}",
            "/notify/{ifCode}/{refundOrderId}"})
    public ResponseEntity doNotify(HttpServletRequest request,
                                   @PathVariable("ifCode") String ifCode,
                                   @PathVariable(value = "refundOrderId", required = false)
                                           Long urlOrderId) {

        Long refundOrderId = null;
        String logPrefix = "进入[" + ifCode + "]退款回调：urlOrderId：["
                + StringUtils.defaultIfEmpty(String.valueOf(urlOrderId), "") + "] ";
        log.info("===== {} =====", logPrefix);

        try {

            // 参数有误
            if (StringUtils.isEmpty(ifCode)) {
                return ResponseEntity.badRequest().body("ifCode is empty");
            }

            //查询退款接口是否存在
            IChannelRefundNoticeService refundNotifyService
                    = SpringBeansUtil.getBean(ifCode + "ChannelRefundNoticeService",
                    IChannelRefundNoticeService.class);

            // 支付通道接口实现不存在
            if (refundNotifyService == null) {
                log.error("{}, interface not exists ", logPrefix);
                return ResponseEntity.badRequest().body("[" + ifCode + "] interface not exists");
            }

            // 解析订单号 和 请求参数
            MutablePair<Long, Object> mutablePair
                    = refundNotifyService.parseParams(request, urlOrderId,
                    IChannelRefundNoticeService.NoticeTypeEnum.DO_NOTIFY);
            if (mutablePair == null) {
                // 解析数据失败， 响应已处理
                log.error("{}, mutablePair is null ", logPrefix);
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "解析数据异常！"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
            }

            // 解析到订单号
            refundOrderId = mutablePair.left;
            log.info("{}, 解析数据为：refundOrderId:{}, params:{}", logPrefix, refundOrderId, mutablePair.getRight());

            if (ObjectUtil.isNotNull(urlOrderId) && !urlOrderId.equals(refundOrderId)) {
                log.error("{}, 订单号不匹配. urlOrderId={}, refundOrderId={} ", logPrefix, urlOrderId, refundOrderId);
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "退款单号不匹配！");
            }

            //获取订单号 和 订单数据
            RefundOrderDO refundOrder = refundOrderService.getById(refundOrderId);

            // 订单不存在
            if (refundOrder == null) {
                log.error("{}, 退款订单不存在. refundOrder={} ", logPrefix, refundOrder);
                return refundNotifyService.doNotifyOrderNotExists(request);
            }
            MchInfoDO mchInfoDO = mchInfoService.getMchInfoById(refundOrder.getMchId());
            MchAppDO mchAppDO = mchAppService.getById(refundOrder.getAppId());
            //查询出商户应用的配置信息
            MchAppConfigContext mchAppConfigContext
                    = configContextQueryService
                    .queryMchInfoAndAppInfo(mchInfoDO.getId(), mchAppDO.getId());

            //调起接口的回调判断
            ChannelRetMsg notifyResult = refundNotifyService.doNotice(request, mutablePair.getRight(), refundOrder, mchAppConfigContext, IChannelRefundNoticeService.NoticeTypeEnum.DO_NOTIFY);

            // 返回null 表明出现异常， 无需处理通知下游等操作。
            if (notifyResult == null || notifyResult.getChannelState() == null || notifyResult.getResponseEntity() == null) {
                log.error("{}, 处理回调事件异常  notifyResult data error, notifyResult ={} ", logPrefix, notifyResult);
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "处理回调事件异常！"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
            }
            // 处理退款订单
            boolean updateOrderSuccess = refundOrderProcessService.handleRefundOrder4Channel(notifyResult, refundOrder);

            // 更新退款订单 异常
            if (!updateOrderSuccess) {
                log.error("{}, updateOrderSuccess = {} ", logPrefix, updateOrderSuccess);
                return refundNotifyService.doNotifyOrderStateUpdateFail(request);
            }

            log.info("===== {}, 订单通知完成。 refundOrderId={}, parseState = {} =====", logPrefix, refundOrderId, notifyResult.getChannelState());

            return notifyResult.getResponseEntity();

        } catch (ServiceException e) {
            log.error("{}, refundOrderId={}, BizException", logPrefix, refundOrderId, e);
            return ResponseEntity.badRequest().body(e.getMessage());

        } catch (ResponseException e) {
            log.error("{}, refundOrderId={}, ResponseException", logPrefix, refundOrderId, e);
            return e.getResponseEntity();

        } catch (Exception e) {
            log.error("{}, refundOrderId={}, 系统异常", logPrefix, refundOrderId, e);
            return ResponseEntity.badRequest().body(e.getMessage());
        }
    }
}
